package com.shisan.tingshu.common.threadpool;

import jakarta.validation.constraints.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程池自动配置类
 */
@Configuration
@EnableConfigurationProperties(ThreadPoolProperties.class)
public class ThreadPoolAutoConfiguration {

    @Value("${spring.application.name}")
    private String appName;

    Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 自定义线程池对象
     * int corePoolSize：核心线程数
     * int maximumPoolSize：最大线程数（JUC的线程池中，当核心线程不够，阻塞队列也满的时候，才会启用）
     * long keepAliveTime：线程最大空闲时间
     * TimeUnit unit：时间单位
     * BlockingQueue<Runnable> workQueue：阻塞队列（核心线程不够的时候启用）。阻塞队列是一个接口，常用的实现类有以下两个：
     * 1、ArrayBlockingQueue：
     * 数组结构组成的有界阻塞队列；
     * 对整个队列加锁，粒度较大，性能较差；
     * 使用的时候一定要传入一个参数，表示队列的长度
     * 2、LinkedBlockingQueue：
     * 链表结构组成的有界阻塞队列；
     * 对队列头和队列尾分别加锁，粒度较小，性能较好；
     * 使用的时候可以不传入参数，不传入参数的时候默认长度为Integer.MAX_VALUE（有OOM的风险），也可以传入一个参数，表示队列的长度
     * ThreadFactory threadFactory：线程工厂（可自定义）
     * RejectedExecutionHandler handler：拒绝策略（有四种，可自定义）
     */
    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolProperties threadPoolProperties) {

        // 对于核心线程数的理论设置：
        // 对于CPU密集型任务（计算为主）：核心线程数 = CPU核数 + 1
        // 对于IO密集型任务（读写为主）：核心线程数 = CPU核数 * 2
        // 实际核心线程数是一定要通过压测某个接口，然后根据压测结果来设置。根据理论计算出来的线程数往往偏小

        // 获取物理机上的逻辑CPU核数
        // int cpuNum = Runtime.getRuntime().availableProcessors();

        int corePoolSize = threadPoolProperties.getCorePoolSize(); // 应该根据压测结果来设置
        int maximumPoolSize = threadPoolProperties.getMaxPoolSize(); // 应该根据压测结果来设置
        long ttl = 30L;
        TimeUnit timeUnit = TimeUnit.SECONDS;
        LinkedBlockingDeque<Runnable> blockingDeque = new LinkedBlockingDeque<>(threadPoolProperties.getQueueSize());
        // 自定义线程工厂
        ThreadFactory threadFactory = new ThreadFactory() {
            // AtomicInteger：线程安全的int类型，可以保证线程安全地自增
            AtomicInteger atomicInteger = new AtomicInteger(0);
            @Override
            public Thread newThread(@NotNull Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("my-customer-【" + appName + "】-" + atomicInteger.incrementAndGet());
                return thread;
            }
        };
        // 自定义拒绝策略
        RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                logger.error("提交给线程池的任务【{}】被拒绝了", r);
                throw new RejectedExecutionException("提交给线程池的任务【" + r + "】被拒绝了");
            }
        };


        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                ttl,
                timeUnit,
                blockingDeque,
                threadFactory,
                rejectedExecutionHandler
        );

        return threadPoolExecutor;
    }
}
